	PAGEWIDTH 96
	TITLE	'CP/M-80 EMULATOR FOR CP/M-86'
;		*** Z80.A86 ***		VERSION 1.2	09/25/84
;
;	WRITTEN BY PAT HESTER	08/12/83
;	MODIFIED BY BILL EARNEST FOR CP/M-86
;	LAST EDIT 9/25/84
;	09/25/84 ADD REL JMPS, REG EXCHGS FOR Z80
;	09/22/84 ADD INTERNAL REPARSE WHICH CPM-86 HASNT
;	09/18/84 CUT .CMD FILE SIZE FOR FASTER LOADING (WDE)
;	09/17/84 FLAG USAGE FIXED, MP/M FUNCTS REPLACED SO
;	CAN BE RUN UNDER CP/M-86. WILL NOW RUN WM.COM OK (WDE)
;
;	GENCMD Z80 EXTRA[MC00]
;
;	INVOCATION:
;		Z80 filename<.typ>	(typ defaults to .COM)
;
;	**** 8080 OP CODES ARE ALLOWED ***
;	**** A FEW Z-80 INSTR. ARE SUPPORTED (NOT MANY) ****
;	**** PROGRAMS MUST USE STRICT CP/M CALLS THRU 0 AND 5 ****
;	**** THE BIOS JUMP TABLE MUST NOT BE ACCESSED ****
;	**** EXCEPT FOR CONIN, CONOU, CONST, LIST ****
;	**** NO GAME PLAYING WITHIN CP/M ****
;
;	REGISTER USAGE:
;		SI	Z80 INSTRUCTION POINTER
;
BDOS		EQU	0E0H		;BDOS INTERRUPT VECTOR
BDOS_LIST	EQU	5		;LIST OUTPUT
BDOS_DIRECT	EQU	6		;DIRECT CONSOLE I/O
BDOS_PRINT	EQU	9		;PRINT STRING
BDOS_INPUT	EQU	10		;READ CONSOLE BUFFER
BDOS_OPENF	EQU	15		;OPEN FILE
BDOS_CLOSEF	EQU	16		;CLOSE FILE
BDOS_READ_NEXT	EQU	20		;READ SEQUENTIAL
BDOS_GET_DISK	EQU	25		;RETURN CURRENT DISK NUMBER
BDOS_DMA_OFFSET	EQU	26		;SET DMA OFFSET
BDOS_DMA_BASE	EQU	51		;SET DMA BASE
BDOS_TERMINATE	EQU	0		;TERMINATE PROCESS
;BDOS_PARSE	EQU	152		;PARSE FILE NAME
;
CR		EQU	0DH		;CARRAIGE RETURN
LF		EQU	0AH		;LINE FEED
BEL		EQU	07H		;RING BELL
;
ZJMP		EQU	0C3H		;Z80 JUMP OP CODE
ZJZ		EQU	0CAH		;Z80 JUMP ON ZERO
ZRET		EQU	0C9H		;Z80 RETURN CODE
ZCALL		EQU	0CDH		;Z80 CALL OP CODE
ZLDCNN		EQU	0EH		;Z80 LD C,nn OP CODE
ZLDENN		EQU	01EH		;Z80 LD E,nn OP CODE
ZLDEC		EQU	059H		;Z80 LD E,C OP CODE
ZORA		EQU	0B7H		;Z80 ORA A CODE

	CSEG
	CALL	INITIALIZE		;SET UP CP/M-80 AREAS, ETC
	CALL	LOAD_Z80		;LOAD Z80 PROGRAM INTO ESEG
	JC	EXIT
	CALL	RUN_Z80			;EMULATION
EXIT:
	MOV	DX,OFFSET MSG_TERMINATE
	CALL	PRINT
	MOV	DL,0			;RELEASE MEMORY
	MOV	CL,BDOS_TERMINATE
	INT	BDOS			;TERMINATE PROCESS
;
INITIALIZE:
	PUSH	ES
	MOV	CL,BDOS_GET_DISK
	INT	BDOS
	MOV	Z80_DISK,AL		;Z80 CURRENT DISK
	POP	ES
	MOV	SI,OFFSET BIOSIMG
	MOV	DI,OFFSET Z80_BIOSV
	MOV	CX,OFFSET BIOIMGE-OFFSET BIOSIMG
	REP MOVSB	;SETUP BIOS VECTORS IN USER SPACE
;
	MOV	SI,OFFSET TBUF+1
	MOV	DI,OFFSET Z80_TAIL
BNKLP:	LODS	AL
	OR	AL,AL
	JZ	HELP
	CMP	AL,' '
	JE	BNKLP
EATLP:	LODS	AL
	OR	AL,AL
	JZ	INIDUN
	CMP	AL,' '
	JNE	EATLP
	MOV	BL,-1
	DEC	SI
	PUSH	SI
TAILLP:	LODS	AL
	STOS	AL
	INC	BL	;COUNT BYTE
	OR	AL,AL	;TEST BYTE
	JNZ	TAILLP
	MOV	Z80_DMA,BL	;TAIL SIZE
	POP	SI
	MOV	DI,OFFSET Z80_FCB
	CALL	GETFN
	MOV	DI,OFFSET Z80_FCB+16
	CALL	GETFN
INIDUN:	RET
;
HELP:
	MOV	DX,OFFSET HLP_MSG
	CALL	PRINT1
	POP	AX	;ADJUST STACK FOR INIT RETURN
	JMP	EXIT
;
GETFN:
	call	nitf
	call	gstart
	jnz	ntblnk
	ret
ntblnk:	call	getdrv
	call	getps
	RET
;
nitf:	push	di
	xor	al,al
	stos	al
	mov	al,' '
	mov	cx,11
	rep stos	al
	xor	al,al
	mov	cx,4
	rep stos	al
	pop	di
	ret
;
gstart:	call	getch
	jz	isdelm
	dec	si
	ret
isdelm:	cmp	al,';'
	jne	ntsemic
	ret
ntsemic:	or	al,al
	jnz	gstart
	ret
;
getch:	lods	al
	cmp	al,'.'
	jne	t1
	ret
t1:	cmp	al,','
	jne	t2
	ret
t2:	cmp	al,';'
	jne	t2a
	ret
t2a:	cmp	al,' '
	jne	t3
	ret
t3:	cmp	al,':'
	jne	t4
	ret
t4:	cmp	al,'='
	jne	t5
	ret
t5:	cmp	al,'<'
	jne	t6
	ret
t6:	cmp	al,'>'
	jne	t7
	ret
t7:	or	al,al
	ret
;
getdrv:
	inc	si
	lods	al
	dec	si
	dec	si
	cmp	al,':'
	jnz	gdret
	lods	al
	sub	al,'@'
	stos	al
	inc	si
	ret
gdret:	inc	di
	ret
;
getps:
	mov	cx,8
	call	getnam
	cmp	al,'.'	;dot terminator?
	jnz	gtpret
ftpont:	cmp	cl,0
	jz	getft
	inc	di
	dec	cl
	jmps	ftpont
getft:	mov	cx,3
	call	getnam
gtpret:	ret
;
getnam:	call	getch
	jnz	gnl1
	ret
gnl1:	cmp	al,'*'
	jz	ambig
	stos	al
	dec	cl
	jnz	getnam
	jmps	getdel
ambig:	mov	al,'?'
qfill:	rep stos al
getdel:	call	getch
	jnz	getdel
	ret
;
LOAD_Z80:
	PUSH	ES
	mov	al,fcbt1
	cmp	al,' '
	jne	typset
	mov	fcbt1,'C'
	mov	fcbt2,'MO'
typset:	MOV	CL,BDOS_OPENF
	MOV	DX,OFFSET FCB
	INT	BDOS			;OPEN Z80 PROGRAM FILE
	INC	AL			;0FFH=ERROR
	POP	ES
	JZ	LOAD_ERROR 
	PUSH	ES
	MOV	CL,BDOS_DMA_BASE
	MOV	DX,ES			;DMA BASE AT ESEG ORIGIN
	INT	BDOS			;SET IT
	MOV	DX,OFFSET Z80_TPA	;BEGIN LOAD THE FILE AT 0100H
LOAD_LOOP:
	PUSH	DX
	MOV	CL,BDOS_DMA_OFFSET
	INT	BDOS			;DMA NOW POINTS TO NEXT 128 BYTE BLOCK
	MOV	CL,BDOS_READ_NEXT
	MOV	DX,OFFSET FCB
	INT	BDOS			;READ NEXT RECORD
	OR	AL,AL			;0 INDICATES READ OK
	JNZ	LOAD_EXIT		;END OF FILE
	POP	DX
	ADD	DX,128			;POINT TO NEXT BLOCK
	JMP	LOAD_LOOP
LOAD_EXIT:
	POP	DX			;RESTORE STACK
	MOV	CL,BDOS_CLOSEF
	MOV	DX,OFFSET FCB
	INT	BDOS			;CLOSE IT UP
	MOV	DX,OFFSET Z80_DMA	;SET DEFAULT DMA
	MOV	CL,BDOS_DMA_OFFSET
	INT	BDOS
	POP	ES
	CLC				;RESET ERROR
	RET
LOAD_ERROR:
	MOV	DX,OFFSET MSG_NO_FILE
	CALL	PRINT
	POP	ES
	STC				;SET ERROR
	RET

RUN_Z80:
	MOV	SI,0100H		;INITIALIZE Z80 IP TO BASE OF TPA
;	PUSHF
RUN_LOOP:
	CMP	SI,0C000H		;TOP OF Z80 MEMORY
	JNB	Z80_RANGE_ERROR		;JUMP OUT OF RANGE
	CMP	SI,0BFF8H		;BDOS CALL VECTOR
	JE	Z80_BDOS_CALL
Z80_OK:
	MOV	DI,ES:[SI]		;DI[L] CONTAINS Z80 INSTRUCTION
	AND	DI,00FFH		;REMOVE HIGH ORDER BYTE
	SAL	DI,1			;MULTIPLY BY 2 FOR JUMP OFFSET
	INC	SI			;BUMP Z80 INSTRUCTION ADDRESS
	MOV	BX,ES:[SI]		;WORD AFTER OP CODE
	MOV	CX,JTABLE[DI]		;CX IS ADDRESS OF OP ROUTINE
;	POPF
;	PUSH	ES
;	LAHF
	SAHF
	CALL	CX			;EXECUTE INSTRUCTION
;	POP	ES
;	PUSHF
	LAHF
	JMP	RUN_LOOP		;NEXT PLEASE
Z80_BDOS_CALL:
	PUSH	AX
	MOV	CH,0
	MOV	CL,Z_C
	MOV	DX,Z_DE
	PUSH	SI
	PUSH	DS
	PUSH	ES
	PUSH	ES
	POP	DS
	INT	BDOS
	POP	ES
	POP	DS
	MOV	Z_HL,BX
	MOV	Z_A,AL
	MOV	Z_DE,DX
	POP	SI
	CALL	Z80_RET
	POP	AX
	JMP	RUN_LOOP
Z80_RANGE_ERROR:
	CMP	SI,0FFFFH
	JE	Z80_END			;BOOT
	PUSH	ES
	MOV	DX,OFFSET MSG_RANGE_ERROR
	CALL	PRINT
	POP	ES
Z80_END:
;	POPF
	RET
;
JTABLE:
	NOLIST
	INCLUDE	JUMPADDR.Z80		;JUMP ADDRESS TABLE
	LIST
EDTBL:
	NOLIST
	INCLUDE EDADDR.Z80
	LIST
CBTBL:
	NOLIST
	INCLUDE CBADDR.Z80
	LIST
;
	INCLUDE	CODE8086.Z80		;8086 INSTS. FOR Z80 OP CODES
	INCLUDE CODECB.Z80
	INCLUDE CODEED.Z80
PRINT:
	PUSH	ES
	PUSH	DX
	MOV	DX,OFFSET MSG_Z80
	CALL	PRINT1
	POP	DX
	CALL	PRINT1
	MOV	DX,OFFSET MSG_CR_LF
	CALL	PRINT1
	POP	ES
	RET
;
PRINT1:	MOV	CL,BDOS_PRINT
	INT	BDOS
	RET

	DSEG
	ORG	05CH
FCB:
	rb	9
fcbt1	rb	1
fcbt2	rw	1
	ORG	06CH
FCB2:
	ORG	080H
TBUF:
	ORG	0100H			;PAST UDA
Z_REGISTERS:			;PRIMARY REGISTER SET
Z_C		RB	1		;REGISTER C
Z_B		RB	1		;REGISTER B
Z_E		RB	1		;REGISTER E
Z_D		RB	1		;REGISTER D
Z_L		RB	1		;REGISTER L
Z_H		RB	1		;REGISTER H
Z_F		RB	1		;REGISTER F...Z80 CONTROL FLAGS
Z_A		RB	1		;REGISTER A
	ORG	0100H
Z_BC		RW	1		;REGISTER BC
Z_DE		RW	1		;REGISTER DE
Z_HL		RW	1		;REGISTER HL
Z_AF		RW	1		;REGISTER AF
Z_SP		DW	0BFF0H		;Z80 STACK POINTER
;
Z_ALTR		RW	3
Z_ALTA		RW	1
Z_X		RW	1
Z_Y		RW	1
Z_TEMP		RW	3	;SCRATCH FOR SWAP

MSG_NO_FILE	DB	'NO Z80 FILE$'
MSG_TERMINATE	DB	'EXITING TO CP/M-86$'
MSG_RANGE_ERROR	DB	'BRANCH OUTSIDE ADDRESS SPACE$'
MSG_Z80_OP	DB	'Z80 OP CODE DETECTED, ONLY 8080 ALLOWED$'
MSG_Z80		DB	CR,LF,'z80-->$'
MSG_CR_LF	DB	CR,LF,'$'
HLP_MSG	DB	'Syntax: Z80 cmd <parameters>',cr,lf
	DB	'Where cmd is 8080 file (default .COM)',cr,lf
	DB	'and <parameters> are the normal arguments.',cr,lf,'$'
;	START OF HI RAM IMAGE
BIOSIMG: 
	DB	ZJMP
	DW	0FFFFH			;JP COLDBOOT
	DB	ZJMP
	DW	0FFFFH			;JP WARMBOOT
	DB	ZJMP
	DW	OFFSET ZBIOS1		;JP CONST
	DB	ZJMP
	DW	OFFSET ZBIOS2		;JP CONIN
	DB	ZJMP
	DW	OFFSET ZBIOS3		;JP CONOUT
	DB	ZJMP
	DW	OFFSET ZBIOS4		;JP LIST
	DB	ZJMP
	DW	0FFFEH		;JP PUNCH (NG)
	DB	ZJMP
	DW	0FFFEH		;JP READER (NG)
	DB	ZJMP
	DW	0FFFEH		;JP HOME (NG)
	DB	ZJMP
	DW	0FFFEH		;JP SELDSK (NG)
	DB	ZJMP
	DW	0FFFEH		;JP SETTRK (NG)
	DB	ZJMP
	DW	0FFFEH		;JP SETSEC (NG)
	DB	ZJMP
	DW	0FFFEH		;JP SETDMA (NG)
	DB	ZJMP
	DW	0FFFEH		;JP READ (NG)
	DB	ZJMP
	DW	0FFFEH		;JP WRITE (NG)
	DB	ZJMP
	DW	0FFFEH		;JP LISTST (NG)
	DB	ZJMP
	DW	0FFFEH		;JP SECTTRANS (NG)
;
	DB	ZLDCNN,BDOS_DIRECT	;LD C,BDOS_DIRECT (RAW I/O)
	DB	ZLDENN,0FEH		;LD E,BDOS_GET_STATUS
	DB	ZCALL
	DW	0BFF8H			;JP BDOS
	DB	ZRET
;
	DB	ZLDCNN,BDOS_DIRECT	;LD C,BDOS_DIRECT (RAW I/O)
	DB	ZLDENN,0FFH		;LD E,BDOS_INPUT_CHAR
	DB	ZCALL
	DW	0BFF8H			;JP BDOS
	DB	ZORA			; ORA A
	DB	ZJZ
	DW	OFFSET ZBIOS2
	DB	ZRET
;
	DB	ZLDEC			;LD E,C
	DB	ZLDCNN,BDOS_DIRECT	;RAW I/O
	DB	ZCALL
	DW	0BFF8H			;JP BDOS
	DB	ZRET
;
	DB	ZLDEC			;LD E,C
	DB	ZLDCNN,BDOS_LIST	;LD C,OUTPUT
	DB	ZCALL
	DW	0BFF8H			;JP BDOS
	DB	ZRET
;
	RB	155
	DW	0FFFFH		;FORCE REBOOT
	RB	14
BIOIMGE:
;
	ESEG
Z80_BOOT	DB	0C3H		;JP BOOT
		DW	0BF03H		;0FFFFH RETURNS TO 8086
Z80_IOBYTE	DB	0		;IOBYTE
Z80_DISK	DB	0		;CURRENT DISK
Z80_BDOS	DB	0C3H		;JMP BDOS
		DW	0BFF8H		;SET FOR 48K TPA
	ORG	05CH			;Z80 FCB
Z80_FCB:
	DB	0,'        ','   ',0,0,0,0	;ONLY ONE VALID
	DB	0,'        ','   ',0,0,0,0	;NOT PARSED
	ORG	080H
Z80_BUF:
Z80_DMA	DB	0
Z80_TAIL:

	ORG	0100H			;BEGINNING OF Z80 TPA
Z80_TPA:
	ORG	0BF00H			;BIOS JUMP TABLE
Z80_BIOSV:
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1
	RB	1 
	RW	1

 ZBIOS1:					;GET CONSOLE STATUS
	RB	8
ZBIOS2:					;GET ONE CHARACTER
	RB	12
ZBIOS3:					;SEND ONE CHARACTER
	RB	7
ZBIOS4:					;ONE CHAR TO LIST
	RB	7
;
	ORG	0BFF0H
	RW	1 ;
	ORG	0BFFFH
	RB	1		;MAKE SURE MP/M-86 DOES

	END
